home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / streaming / qtspacketizerreassembler / imaaudiortp / sources / rtpmpimaaudio.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  52.5 KB  |  2,084 lines

  1. /*
  2.     File:        RTPMPIMAAudio.c
  3.  
  4.     Contains:    Definition of IMA Audio RTPMediaPacketizer
  5.  
  6.     Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  7.     
  8.     
  9.     
  10.     OVERVIEW
  11.     
  12.     QuickTime Streaming software uses an RTPMediaPacketizer to encapsulate
  13.     sample data in network packets.  When preparing to packetize sample data,
  14.     Streaming software first determines a packetizer's capabilities and
  15.     operational parameters.  If the packetizer is suitable, the Streaming
  16.     software provides the packetizer with an RTPPacketBuilder.  The packetizer
  17.     uses the RTPPacketBuilder to construct network packets from sample data.
  18.     The Streaming software specifies what sample data to packetize by calling
  19.     the packetizer's RTPMPSetSampleData() implementation.
  20.     
  21.     This packetizer implements the following interface and delegates all other
  22.     calls to a base RTPMediaPacketizer defined by QuickTime Streaming.
  23.         
  24.         
  25.         STANDARD COMPONENT INTERFACE
  26.         ----------------------------
  27.         
  28.         CallComponentOpen()                Allocate and initialize storage for
  29.                                         instance variables.
  30.         
  31.         CallComponentClose()            Reverse the effects of
  32.                                         CallComponentOpen().
  33.         
  34.         CallComponentVersion()            Return the instance's version.
  35.         
  36.         CallComponentTarget()            Update the instance's inheritance graph.
  37.         
  38.         
  39.         
  40.         RTP MEDIA PACKETIZER INTERFACE
  41.         ------------------------------
  42.         
  43.         RTPMPInitialize()                Prepare to packetize sample data.
  44.         
  45.         RTPMPPreflightMedia()            Determine whether the packetizer can
  46.                                         packetize the described data.
  47.         
  48.         RTPMPSetSampleData()            Use the instance's RTPPacketBuilder to
  49.                                         packetize sample data.
  50.         
  51.         RTPMPFlush()                    Finish any packetization in progress.
  52.         
  53.         RTPMPReset()                    Abort any packetization in progress.
  54.         
  55.         RTPMPGetInfo()                    Return the requested information.
  56.         
  57.         RTPMPSetTimeScale()
  58.         
  59.         RTPMPGetTimeScale()
  60.         
  61.         RTPMPSetTimeBase()
  62.         
  63.         RTPMPGetTimeBase()
  64.         
  65.         RTPMPHasCharacteristic()
  66.         
  67.         RTPMPSetPacketBuilder()
  68.         
  69.         RTPMPGetPacketBuilder()
  70.         
  71.         RTPMPSetMediaType()
  72.         
  73.         RTPMPGetMediaType()
  74.         
  75.         RTPMPSetMaxPacketSize()
  76.         
  77.         RTPMPGetMaxPacketSize()
  78.         
  79.         RTPMPSetMaxPacketDuration()
  80.         
  81.         RTPMPGetMaxPacketDuration()        
  82.         
  83.         RTPMPDoUserDialog()                Present a dialog of user-adjustable
  84.                                         options.
  85.         
  86.         RTPMPSetSettingsFromAtomContainerAtAtom()
  87.                                         Update instance variables with saved
  88.                                         user settings.
  89.         
  90.         RTPMPGetSettingsIntoAtomContainerAtAtom()
  91.                                         Return current settings of user
  92.                                         adjustable options.
  93.                                         
  94.         RTPMPGetMediaSettingsAsText()    Return current settings of user
  95.                                         adjustable options as a string.
  96. */
  97.  
  98.  
  99.  
  100. /* ---------------------------------------------------------------------------
  101.  *        H E A D E R S
  102.  * ---------------------------------------------------------------------------
  103.  */
  104.  
  105. #include "RTPMPIMAAudio.h"
  106. #include "RTPMPIMAAudioResources.h"
  107. #include <FixMath.h>
  108. #include <Math64.h>
  109. #include <Resources.h>
  110. #include <TextUtils.h>
  111.  
  112.  
  113.  
  114. /* ---------------------------------------------------------------------------
  115.  *        R T P    M E D I A    P A C K E T I Z E R    P R O T O T Y P E S
  116.  * ---------------------------------------------------------------------------
  117.  *
  118.  *    QTStreamingComponents.k.h uses these macros to declare prototypes for
  119.  *    the RTPMediaPacketizer calls defined in this file.
  120.  *
  121.  */
  122.  
  123. #define RTPMP_BASENAME()                RTPMPIMAAudio_
  124. #define RTPMP_GLOBALS()                    RTPMPIMAAudioInstanceData **
  125.  
  126. #include <QTStreamingComponents.k.h>
  127.  
  128.  
  129.  
  130. /* ---------------------------------------------------------------------------
  131.  *        C O M P O N E N T    D I S P A T C H    H E L P E R
  132.  * ---------------------------------------------------------------------------
  133.  *
  134.  *    ComponentDispatchHelper.c uses these macros to define a dispatcher and to
  135.  *    declare prototypes for the core component calls defined in this file.  For
  136.  *    Mac OS, it defines the routine descriptor that serves as the component
  137.  *    entry point.  The name of the routine descriptor is the macro expansion of
  138.  *        
  139.  *        CALLCOMPONENT_BASENAME()##ComponentDispatchRD
  140.  *    
  141.  *    The name of the dispatcher is the macro expansion of
  142.  *    
  143.  *        CALLCOMPONENT_BASENAME()##ComponentDispatch
  144.  *
  145.  */
  146.  
  147. #define CALLCOMPONENT_BASENAME()        RTPMP_BASENAME()
  148. #define CALLCOMPONENT_GLOBALS()            RTPMP_GLOBALS() storage
  149. #define COMPONENT_DISPATCH_FILE            "RTPMPIMAAudioDispatch.h"
  150. #define COMPONENT_C_DISPATCHER            1
  151. #define COMPONENT_UPP_SELECT_ROOT()        RTPMP
  152. #define GET_DELEGATE_COMPONENT()        ( ( **storage ).itsBase )
  153.  
  154. #include <ComponentDispatchHelper.c>
  155.  
  156.  
  157.  
  158. #pragma mark *        INTERNAL IMPLEMENTATION
  159. #pragma mark -
  160. /* ---------------------------------------------------------------------------
  161.  *        I N T E R N A L    I M P L E M E N T A T I O N
  162.  * ---------------------------------------------------------------------------
  163.  */
  164.  
  165. #if TARGET_OS_WIN32
  166. #    define DragWindow( window, startPt, boundsRect )
  167. #endif
  168.  
  169.  
  170.  
  171. enum
  172. {
  173.     __kNoFlags                        = 0,
  174.     __kFlush                        = true,
  175.     __kDontFlush                    = !__kFlush,
  176.     __kDefaultPacketDurationLimit    = 200,            /* 200ms.  See RFC 1890, section 4.1 */
  177.     __kDefaultInterleaveCount        = 3,
  178.     __kTypicalMTUSize                = 1500,            /* Ethernet */
  179.     __kTypicalNetworkHeaderSize        = 20,            /* IP, no options */
  180.     __kTypicalTransportHeaderSize    = 8,            /* UDP */
  181.     __kTypicalRTPHeaderSize            = 12,            /* no CSRCs, no extension */
  182.     __kDefaultPacketSizeLimit        =
  183.         __kTypicalMTUSize - __kTypicalNetworkHeaderSize - __kTypicalTransportHeaderSize -
  184.         __kTypicalRTPHeaderSize
  185. };
  186.  
  187. enum
  188. {
  189.     __kOKButton                = 1,
  190.     __kCancelButton            = 2,
  191.     __kInterleavingMenu        = 3
  192. };
  193.  
  194. enum
  195. {
  196.     __kInterleaveCountAtomType = 'ilvc'
  197. };
  198.  
  199.  
  200.  
  201. typedef UInt32    __TStoredInterleaveCount;
  202.  
  203.  
  204.  
  205. /* ---------------------------------------------------------------------------
  206.  *        __Drag()
  207.  * ---------------------------------------------------------------------------
  208.  *
  209.  *    Drag the dialog window on mouseDown.
  210.  *
  211.  */
  212.  
  213. static
  214. Boolean
  215. __Drag(
  216.     DialogPtr                aDialog,
  217.     const EventRecord *        anEvent )
  218. {
  219.     Boolean        theResult = false;
  220.     WindowPtr    theWindow;
  221.     short        thePart;
  222.     Rect        theBoundary;
  223.     
  224.     
  225.     if( anEvent->what == mouseDown )
  226.     {
  227.         thePart = MacFindWindow( anEvent->where, &theWindow );
  228.         
  229.         if( theWindow == aDialog  &&  thePart == inDrag )
  230.         {
  231.             theBoundary = ( **GetGrayRgn() ).rgnBBox;
  232.             
  233.             DragWindow( aDialog, anEvent->where, &theBoundary );
  234.             
  235.             theResult = true;
  236.         }
  237.     }
  238.     
  239.     return( theResult );
  240. }
  241.  
  242.  
  243.  
  244. /* ---------------------------------------------------------------------------
  245.  *        __SettingsDialogFilter()
  246.  * ---------------------------------------------------------------------------
  247.  *
  248.  *    Drag the dialog window if appropriate.  Otherwise dispatch first to the
  249.  *    custom event filter, if any, passed to RTPMPDoUserDialog(), and then, if
  250.  *    necessary, to the standard event filter.
  251.  *
  252.  */
  253.  
  254. static
  255. pascal
  256. Boolean
  257. __SettingsDialogFilter(
  258.     DialogPtr        aDialog,
  259.     EventRecord *    anEvent,
  260.     short *            anItem )
  261. {
  262.     Boolean            theResult = false;
  263.     ModalFilterUPP    theCustomFilter;
  264.     
  265.     
  266.     if( __Drag( aDialog, anEvent ) )
  267.     {
  268.         *anItem = 0;
  269.         theResult = true;
  270.     }
  271.     
  272.     else
  273.     {
  274.         theCustomFilter = REINTERPRET_CAST( ModalFilterUPP )( GetWRefCon( aDialog ) );
  275.         
  276.         if( theCustomFilter )
  277.             theResult = CallModalFilterProc( theCustomFilter, aDialog, anEvent, anItem );
  278.         
  279.         if( !theResult )
  280.             theResult = StdFilterProc( aDialog, anEvent, anItem );
  281.     }
  282.     
  283.     return( theResult );
  284. }
  285.  
  286.  
  287.  
  288. /* ---------------------------------------------------------------------------
  289.  *        __GreatestCommonFactor()
  290.  * ---------------------------------------------------------------------------
  291.  *
  292.  *    Compute the greatest common factor of two positive integers.
  293.  *
  294.  */
  295.  
  296. static
  297. UInt32
  298. __GreatestCommonFactor(
  299.     UInt32    inDividend,
  300.     UInt32    inDivisor )
  301. {
  302.     UInt32    theRemainder;
  303.     
  304.     
  305.     while( inDivisor )
  306.     {
  307.         theRemainder = inDividend % inDivisor;
  308.         inDividend = inDivisor;
  309.         inDivisor = theRemainder;
  310.     }
  311.     
  312.     return( inDividend );
  313. }
  314.  
  315.  
  316.  
  317. /* ---------------------------------------------------------------------------
  318.  *        __LockInstanceData()
  319.  * ---------------------------------------------------------------------------
  320.  *
  321.  *    Lock relocatable block containing instance data.
  322.  *
  323.  */
  324.  
  325. static
  326. void
  327. __LockInstanceData(
  328.     RTPMPIMAAudioInstanceData **    inGlobals )
  329. {
  330.     if( !( **inGlobals ).itsLockCount )
  331.     {
  332.         if( ( **inGlobals ).itsInSystemHeap )
  333.             HLock( REINTERPRET_CAST( Handle )( inGlobals ) );
  334.         else
  335.             HLockHi( REINTERPRET_CAST( Handle )( inGlobals ) );
  336.     }
  337.     
  338.     ( **inGlobals ).itsLockCount++;
  339. }
  340.  
  341.  
  342.  
  343. /* ---------------------------------------------------------------------------
  344.  *        __UnlockInstanceData()
  345.  * ---------------------------------------------------------------------------
  346.  *
  347.  *    Unlock relocatable block containing instance data.
  348.  *
  349.  */
  350.  
  351. static
  352. void
  353. __UnlockInstanceData(
  354.     RTPMPIMAAudioInstanceData **    inGlobals )
  355. {
  356.     --( **inGlobals ).itsLockCount;
  357.     
  358.     if( !( **inGlobals ).itsLockCount )
  359.         HUnlock( REINTERPRET_CAST( Handle )( inGlobals ) );
  360. }
  361.  
  362.  
  363.  
  364. /* ---------------------------------------------------------------------------
  365.  *        __InterleaveGroupFrameCount()
  366.  * ---------------------------------------------------------------------------
  367.  *
  368.  *    Compute the number of frames in an interleave group according to the
  369.  *    following constraints:
  370.  *
  371.  *        - no packet exceeds the packet size limit
  372.  *
  373.  *        - no packet exceeds the packet duration limit
  374.  *
  375.  *        - the frame count is a multiple of the channel count
  376.  *
  377.  *        - the group duration is an integer number of clock cycles
  378.  *
  379.  */
  380.  
  381. static
  382. UInt32
  383. __InterleaveGroupFrameCount(
  384.     RTPMPIMAAudioInstanceData **    inGlobals )
  385. {
  386.     UInt32    theResult;
  387.     UInt64    theDurationLimit;
  388.     UInt64    theSampleRate;
  389.     UInt32    theTimewiseLimit;
  390.     UInt32    theInterleaveCount;
  391.     UInt32    theChannelCount;
  392.     UInt32    theFrameDurationRemainder;
  393.     UInt32    theIntegerDurationFrameCount;
  394.     UInt32    theConstrainingFactor;
  395.     UInt32    theCommonFactor;
  396.     
  397.     
  398.     /* Compute size-wise limit per payload. */
  399.     
  400.     theResult =
  401.         ( ( **inGlobals ).itsPayloadSizeLimit -
  402.             ( sizeof( IMAAudioPayload ) - sizeof( IMAAudioFrame ) ) ) /
  403.         sizeof( IMAAudioFrame );
  404.     
  405.     
  406.     /* Compute time-wise limit per payload. */
  407.     
  408.     theDurationLimit = U64SetU( ( **inGlobals ).itsPayloadDurationLimit );
  409.     theSampleRate =
  410.         U64SetU( IMAAudioPayloadSampleRate( &( **inGlobals ).itsPayloadAttributes ) );
  411.     
  412.     theTimewiseLimit =
  413.         Fix2Long(
  414.             U32SetU(
  415.                 U64Div(
  416.                     U64Multiply( theDurationLimit, theSampleRate ),
  417.                     U64SetU( 1000UL * kIMAAudioPayloadFrameSampleCount ) ) ) );
  418.     
  419.     
  420.     /* Select lesser limit. */
  421.     
  422.     if( theResult > theTimewiseLimit )
  423.         theResult = theTimewiseLimit;
  424.     
  425.     
  426.     /* Compute limit for entire interleave group. */
  427.     
  428.     theInterleaveCount =
  429.         IMAAudioPayloadInterleaveCount( &( **inGlobals ).itsPayloadAttributes );
  430.     
  431.     theResult *= theInterleaveCount;
  432.     
  433.     
  434.     /*    Compute the least number of frames that, given their sample rate,
  435.         have an integer duration with respect to the RTP clock rate of
  436.         55125 Hz.  As explained in IMAAudioPayload.h, the integer-duration
  437.         frame count will be no greater than four.  An interleave group has
  438.         integer duration when its frame count is a multiple of the integer-
  439.         duration frame count. */
  440.     
  441.     theFrameDurationRemainder =
  442.         U64Mod(
  443.             U64Multiply(
  444.                 U64SetU( STATIC_CAST( UInt32 )( kIMAAudioPayloadRTPTimeScale ) << 16 ),
  445.                 U64SetU( kIMAAudioPayloadFrameSampleCount ) ),
  446.             theSampleRate );
  447.     
  448.     if( theFrameDurationRemainder )
  449.     {
  450.         theIntegerDurationFrameCount =
  451.             U32SetU( U64Div( theSampleRate, theFrameDurationRemainder ) );
  452.     }
  453.     
  454.     else
  455.     {
  456.         theIntegerDurationFrameCount = 1;
  457.     }
  458.     
  459.     
  460.     /*    Restrict group frame count to a multiple of both the channel count and
  461.         the integer-duration frame count. */
  462.     
  463.     theChannelCount = IMAAudioPayloadChannelCount( &( **inGlobals ).itsPayloadAttributes );
  464.     
  465.     theCommonFactor =
  466.         __GreatestCommonFactor( theIntegerDurationFrameCount, theChannelCount );
  467.     
  468.     theConstrainingFactor =
  469.         ( theIntegerDurationFrameCount / theCommonFactor ) *
  470.             ( theChannelCount / theCommonFactor );
  471.     
  472.     theResult = ( theResult / theConstrainingFactor ) * theConstrainingFactor;
  473.     
  474.     
  475.     return( theResult );
  476. }
  477.  
  478.  
  479.  
  480. /* ---------------------------------------------------------------------------
  481.  *        __UpdateLimits()
  482.  * ---------------------------------------------------------------------------
  483.  *
  484.  *    Update values used to construct network packets.
  485.  *
  486.  */
  487.  
  488. static
  489. void
  490. __UpdateLimits(
  491.     RTPMPIMAAudioInstanceData **    inGlobals )
  492. {
  493.     if( ( **inGlobals ).itsPayloadAttributesInitialized )
  494.     {
  495.         /*    Update count of frames in each interleave group. */
  496.         
  497.         ( **inGlobals ).itsInterleaveGroupFrameCount =
  498.             __InterleaveGroupFrameCount( inGlobals );
  499.     }
  500. }
  501.  
  502.  
  503.  
  504. /* ---------------------------------------------------------------------------
  505.  *        __UpdateSampleDescription()
  506.  * ---------------------------------------------------------------------------
  507.  *
  508.  *    Determine whether the SampleDescription of incoming sample data has
  509.  *    changed and update instance variables accordingly.
  510.  *
  511.  */
  512.  
  513. static
  514. ComponentResult
  515. __UpdateSampleDescription(
  516.     RTPMPIMAAudioInstanceData **    inGlobals,
  517.     const RTPMPSampleDataParams *    inSampleData )
  518. {
  519.     ComponentResult            theError = noErr;
  520.     SInt32                    theFlags;
  521.     SoundDescriptionHandle    theDescription;
  522.     CompressionInfo            theCompressionInfo;
  523.     UnsignedFixed            thePayloadSampleRate;
  524.     
  525.     
  526.     /*    Check the SampleDescription if it is the first description or if the cached
  527.         sample description seed doesn't match the current seed. */
  528.     
  529.     if(
  530.         !( **inGlobals ).itsPayloadAttributesInitialized  ||
  531.         ( **inGlobals ).itsSampleDescriptionSeed != inSampleData->sampleDescSeed )
  532.     {
  533.         /*    If the RTPMPSetSampleData() implementation queues data, then any
  534.             queued sample data, which uses the obsolete SampleDescription, must
  535.             be flushed before updating to the new SampleDescription. */
  536.         
  537.         theError = RTPMPFlush( ( **inGlobals ).itsFinalDerivation, 0, &theFlags );
  538.         
  539.         if( !theError )
  540.         {
  541.             theDescription =
  542.                 REINTERPRET_CAST( SoundDescriptionHandle )(
  543.                     inSampleData->sampleDescription );
  544.             
  545.             theError =
  546.                 GetCompressionInfo(
  547.                     fixedCompression, ( **theDescription ).dataFormat,
  548.                     ( **theDescription ).numChannels, ( **theDescription ).sampleSize,
  549.                     &theCompressionInfo );
  550.             
  551.             
  552.             /*    Update the payload header that the packetizer includes in each network
  553.                 packet. */
  554.             
  555.             IMAAudioPayloadSetChannelCount(
  556.                 &( **inGlobals ).itsPayloadAttributes, ( **theDescription ).numChannels );
  557.             
  558.             thePayloadSampleRate =
  559.                 IMAAudioPayloadSetSampleRate(
  560.                     &( **inGlobals ).itsPayloadAttributes,
  561.                     ( **theDescription ).sampleRate );
  562.             
  563.             ( **inGlobals ).itsPayloadAttributesInitialized = true;
  564.             
  565.             
  566.             IMAAudioQueueSetFlowControl(
  567.                 &( **inGlobals ).itsAudioQueue, ( **theDescription ).sampleRate,
  568.                 thePayloadSampleRate, ( **theDescription ).numChannels );
  569.             
  570.             
  571.             /*    Update values used to construct network packets. */
  572.             
  573.             __UpdateLimits( inGlobals );
  574.             
  575.             
  576.             /*    Update the cached sample description seed to indicate that the
  577.                 packetizer state is now consistent with the new SampleDescription. */
  578.             
  579.             ( **inGlobals ).itsSampleDescriptionSeed = inSampleData->sampleDescSeed;
  580.         }
  581.     }
  582.     
  583.     return( theError );
  584. }
  585.  
  586.  
  587.  
  588. /* ---------------------------------------------------------------------------
  589.  *        __SampleBlockDuration()
  590.  * ---------------------------------------------------------------------------
  591.  *
  592.  *    Compute the duration of the described sample block.
  593.  *
  594.  */
  595.  
  596. static
  597. UInt32
  598. __SampleBlockDuration(
  599.     const RTPMPSampleDataParams *    inSampleData )
  600. {
  601.     UInt32                    theResult;
  602.     UInt32                    theSampleCount;
  603.     SoundDescriptionHandle    theDescription;
  604.     UInt64                    theFixedSampleCount;
  605.     
  606.     
  607.     if( inSampleData->duration )
  608.     {
  609.         theResult = inSampleData->duration;
  610.     }
  611.     
  612.     else
  613.     {
  614.         theDescription =
  615.             REINTERPRET_CAST( SoundDescriptionHandle )( inSampleData->sampleDescription );
  616.         
  617.         theSampleCount =
  618.             kIMAAudioPayloadFrameSampleCount *
  619.             ( inSampleData->dataLength / sizeof( IMAAudioFrame ) );
  620.         
  621.         theFixedSampleCount = U64Multiply( U64SetU( theSampleCount ), U64SetU( fixed1 ) );
  622.         
  623.         theResult =
  624.             U32SetU(
  625.                 U64Div(
  626.                     U64Multiply(
  627.                         theFixedSampleCount, U64SetU( kIMAAudioPayloadRTPTimeScale ) ),
  628.                     U64SetU( ( **theDescription ).sampleRate ) ) );
  629.     }
  630.     
  631.     return( theResult );
  632. }
  633.  
  634.  
  635.  
  636. /* ---------------------------------------------------------------------------
  637.  *        __BeginInterleaveGroup()
  638.  * ---------------------------------------------------------------------------
  639.  *
  640.  *    Use the RTPPacketBuilder to create a new packet group and all the packets
  641.  *    in that group.  For this packetizer, a packet group contains one
  642.  *    interleave group.
  643.  *    
  644.  *    Each network packet consists of a fixed header followed by sample data.
  645.  *    This function adds the fixed header to each packet.
  646.  *
  647.  */
  648.  
  649. static
  650. ComponentResult
  651. __BeginInterleaveGroup(
  652.     const IMAAudioPayload *        inPayloadAttributes,
  653.     TimeValue64                    inTimestamp,
  654.     UInt32                        inFrameCount,
  655.     RTPPacketBuilder            inPacketBuilder,
  656.     RTPPacketGroupRef *            outPacketGroup,
  657.     RTPPacketRef *                outPackets )
  658. {
  659.     ComponentResult        theResult;
  660.     UInt32                theInterleaveCount;
  661.     UInt32                thePayloadFrameCount;
  662.     UInt32                theIndex;
  663.     IMAAudioPayload        theHeader;
  664.     UInt32                theHeaderSize;
  665.     UInt32                thePayloadSizeLimit;
  666.     
  667.     
  668.     theResult =
  669.         RTPPBBeginPacketGroup( inPacketBuilder, __kNoFlags, inTimestamp, outPacketGroup );
  670.     
  671.     theInterleaveCount = IMAAudioPayloadInterleaveCount( inPayloadAttributes );
  672.     thePayloadFrameCount = ( inFrameCount + theInterleaveCount - 1 ) / theInterleaveCount;
  673.     
  674.     theHeader = *inPayloadAttributes;
  675.     theHeaderSize = sizeof( theHeader ) - sizeof( IMAAudioFrame );
  676.     
  677.     thePayloadSizeLimit =
  678.         theHeaderSize + ( thePayloadFrameCount * sizeof( IMAAudioFrame ) );
  679.     
  680.     
  681.     /*    If there aren't enough frames to fill an entire interleave group, omit the
  682.         empty packets. */
  683.     
  684.     if( theInterleaveCount > inFrameCount )
  685.         theInterleaveCount = inFrameCount;
  686.     
  687.     for( theIndex = 0; theIndex < theInterleaveCount  &&  theResult == noErr; theIndex++ )
  688.     {
  689.         theResult =
  690.             RTPPBBeginPacket(
  691.                 inPacketBuilder, __kNoFlags, *outPacketGroup, thePayloadSizeLimit,
  692.                 &outPackets[ theIndex ] );
  693.         
  694.         if( theResult == noErr )
  695.         {
  696.             /*    The header is added to the network packet as literal data.  Literal
  697.                 data is written directly to the network packet.  If the
  698.                 RTPPacketBuilder is storing network packet data to disk, it must
  699.                 store a copy of literal data. */
  700.             
  701.             theResult =
  702.                 RTPPBAddPacketLiteralData(
  703.                     inPacketBuilder, __kNoFlags, *outPacketGroup, outPackets[ theIndex ],
  704.                     REINTERPRET_CAST( UInt8 * )( &theHeader ), theHeaderSize, NULL );
  705.             
  706.             IMAAudioPayloadIncrementInterleaveIndex( &theHeader );
  707.         }
  708.     }
  709.     
  710.     return( theResult );
  711. }
  712.  
  713.  
  714.  
  715. /* ---------------------------------------------------------------------------
  716.  *        __EndInterleaveGroup()
  717.  * ---------------------------------------------------------------------------
  718.  *
  719.  *    Use the RTPPacketBuilder to close the current packet group and all its
  720.  *    packets.
  721.  *
  722.  */
  723.  
  724. static
  725. ComponentResult
  726. __EndInterleaveGroup(
  727.     const IMAAudioPayload *        inPayloadAttributes,
  728.     UInt32                        inFrameCount,
  729.     RTPPacketBuilder            inPacketBuilder,
  730.     RTPPacketGroupRef            inPacketGroup,
  731.     const RTPPacketRef *        inPackets )
  732. {
  733.     ComponentResult        theResult = noErr;
  734.     UnsignedFixed        theSampleRate;
  735.     UInt32                theDuration;
  736.     UInt32                theInterleaveCount;
  737.     UInt32                theIndex;
  738.     
  739.     
  740.     theSampleRate = IMAAudioPayloadSampleRate( inPayloadAttributes );
  741.     
  742.     theDuration =
  743.         U32SetU(
  744.             U64Div(
  745.                 U64Multiply(
  746.                     U64SetU( inFrameCount * kIMAAudioPayloadFrameSampleCount ),
  747.                     U64SetU( STATIC_CAST( UInt32 )( kIMAAudioPayloadRTPTimeScale ) << 16 ) ),
  748.                 U64SetU( theSampleRate ) ) );
  749.     
  750.     theDuration /= IMAAudioPayloadChannelCount( inPayloadAttributes );
  751.     
  752.     theInterleaveCount = IMAAudioPayloadInterleaveCount( inPayloadAttributes );
  753.     
  754.     
  755.     /*    If there aren't enough frames to fill an entire interleave group, the empty
  756.         packets have been omitted. */
  757.     
  758.     if( theInterleaveCount > inFrameCount )
  759.         theInterleaveCount = inFrameCount;
  760.     
  761.     
  762.     /*    To simplify reassembly, this packetizer uses the timestamp of the start
  763.         of the group as the timestamp for each network packet in the group.  When
  764.         reassembling, the derived RTPReassembler relies on the QuickTime Streaming
  765.         base RTPReassembler to group together packets that have the same timestamp.
  766.         
  767.         A packet's duration is the time between its timestamp and the timestamp
  768.         of the next packet.  Since these packets share the same timestamp, most
  769.         have zero duration.  The last packet in the group reflects the duration
  770.         of the entire group. */
  771.     
  772.     for(
  773.         theIndex = 0; theIndex < ( theInterleaveCount - 1 )  &&  theResult == noErr;
  774.         theIndex++ )
  775.     {
  776.         theResult =
  777.             RTPPBEndPacket(
  778.                 inPacketBuilder, __kNoFlags, inPacketGroup, inPackets[ theIndex ],
  779.                 0 /* inTimeOffset */ , 0 /* inDuration */ );
  780.     }
  781.     
  782.     if( theResult == noErr )
  783.     {
  784.         /*    The packetizer sets the RTP/AVP marker bit in the last network
  785.             packet of an interleave group.  The QuickTime Streaming base
  786.             RTPReassembler can better assist in reassembling the payload data
  787.             if this bit is used to mark the end of a packet group. */
  788.         
  789.         theResult =
  790.             RTPPBEndPacket(
  791.                 inPacketBuilder, kRTPPBSetMarkerFlag, inPacketGroup, inPackets[ theIndex ],
  792.                 0, theDuration );
  793.         
  794.         if( theResult == noErr )
  795.         {
  796.             /*    For this packetizer, every group contains only sync samples.  That
  797.                 means the sample data for the group can be decoded independently of
  798.                 any previous sample data.  When randomly accessing stored movies,
  799.                 a streaming server can look for sync samples. */
  800.             
  801.             theResult =
  802.                 RTPPBEndPacketGroup( inPacketBuilder, kRTPPBSyncSampleFlag, inPacketGroup );
  803.         }
  804.         
  805.         else
  806.         {
  807.             RTPPBEndPacketGroup( inPacketBuilder, kRTPPBDontSendFlag, inPacketGroup );
  808.         }
  809.     }
  810.     
  811.     return( theResult );
  812. }
  813.  
  814.  
  815.  
  816. /* ---------------------------------------------------------------------------
  817.  *        __PacketizeInterleaveGroup()
  818.  * ---------------------------------------------------------------------------
  819.  *
  820.  *    Use the RTPPacketBuilder and the queued sample data to construct a single
  821.  *    interleave group of network packets.
  822.  *    
  823.  */
  824.  
  825. static
  826. ComponentResult
  827. __PacketizeInterleaveGroup(
  828.     IMAAudioQueue *                inAudioQueue,
  829.     const IMAAudioPayload *        inPayloadAttributes,
  830.     UInt32                        inInterleaveGroupFrameCount,
  831.     RTPPacketBuilder            inPacketBuilder )
  832. {
  833.     ComponentResult            theResult;
  834.     IMAAudioPayload            thePayloadAttributes;
  835.     UInt32                    theFrameCount;
  836.     UInt32                    theInterleaveCount;
  837.     IMAAudioQueueElement    theFrameInfo;
  838.     RTPPacketGroupRef        thePacketGroup;
  839.     RTPPacketRef            thePackets[ kIMAAudioPayloadInterleaveCountLimit ];
  840.     UInt32                    theFrameIndex;
  841.     
  842.     
  843.     /* Get the total queued frame count. */
  844.     
  845.     theFrameCount = IMAAudioQueueCount( inAudioQueue );
  846.     
  847.     if( theFrameCount )
  848.     {
  849.         /* Limit the frame count to a single interleave group. */
  850.         
  851.         if( theFrameCount >= inInterleaveGroupFrameCount )
  852.             theFrameCount = inInterleaveGroupFrameCount;
  853.         
  854.         thePayloadAttributes = *inPayloadAttributes;
  855.         
  856.         theInterleaveCount = IMAAudioPayloadInterleaveCount( &thePayloadAttributes );
  857.         
  858.         IMAAudioPayloadSetInterleaving(
  859.             &thePayloadAttributes, theInterleaveCount, theFrameCount );
  860.         
  861.         
  862.         /* Initialize the interleave group. */
  863.         
  864.         IMAAudioQueueDequeue( inAudioQueue, &theFrameInfo );
  865.         
  866.         theResult =
  867.             __BeginInterleaveGroup(
  868.                 &thePayloadAttributes, theFrameInfo.itsTimestamp, theFrameCount,
  869.                 inPacketBuilder, &thePacketGroup, thePackets );
  870.         
  871.         
  872.         /* Interleave audio frames into network packets. */
  873.         
  874.         theFrameIndex = 0;
  875.         
  876.         do
  877.         {
  878.             /*    The RTPPacketBuilder provides a routine specifically for adding
  879.                 sample data.  For stored movies, the RTPPacketBuilder need not
  880.                 store a copy of sample data, since the data is already stored
  881.                 in the movie. */
  882.             
  883.             theResult =
  884.                 RTPPBAddPacketSampleData(
  885.                     inPacketBuilder, __kNoFlags, thePacketGroup,
  886.                     thePackets[ theFrameIndex % theInterleaveCount ],
  887.                     theFrameInfo.itsSampleDataParams, theFrameInfo.itsOffset,
  888.                     sizeof( IMAAudioFrame ), NULL );
  889.             
  890.             theFrameIndex++;
  891.         }
  892.         while(
  893.             theResult == noErr  &&  theFrameIndex < theFrameCount  &&
  894.             IMAAudioQueueDequeue( inAudioQueue, &theFrameInfo ) );
  895.         
  896.         
  897.         /* End the interleave group. */
  898.         
  899.         if( theResult == noErr )
  900.         {
  901.             theResult =
  902.                 __EndInterleaveGroup(
  903.                     &thePayloadAttributes, theFrameCount, inPacketBuilder,
  904.                     thePacketGroup, thePackets );
  905.         }
  906.     }
  907.     
  908.     return( theResult );
  909. }
  910.  
  911.  
  912.  
  913. /* ---------------------------------------------------------------------------
  914.  *        __ProcessAudioQueue()
  915.  * ---------------------------------------------------------------------------
  916.  *
  917.  *    When flushing, packetize all queued audio data.  Otherwise, packetize
  918.  *    interleave groups continuously until there is not enough data to fill an
  919.  *    interleave group.
  920.  *
  921.  */
  922.  
  923. static
  924. ComponentResult
  925. __ProcessAudioQueue(
  926.     RTPMPIMAAudioInstanceData **    inGlobals,
  927.     Boolean                            inFlush )
  928. {
  929.     ComponentResult        theResult = noErr;
  930.     IMAAudioPayload        thePayloadAttributes = ( **inGlobals ).itsPayloadAttributes;
  931.     UInt32                theMinimumFrameCount;
  932.     UInt32                theFrameCount;
  933.     
  934.     
  935.     __LockInstanceData( inGlobals );
  936.     
  937.     if( inFlush )
  938.         theMinimumFrameCount = 1;
  939.     else
  940.         theMinimumFrameCount = ( **inGlobals ).itsInterleaveGroupFrameCount;
  941.     
  942.     for(
  943.         theFrameCount = IMAAudioQueueCount( &( **inGlobals ).itsAudioQueue );
  944.         theFrameCount >= theMinimumFrameCount  &&  theResult == noErr;
  945.         theFrameCount = IMAAudioQueueCount( &( **inGlobals ).itsAudioQueue ) )
  946.     {
  947.         if( theFrameCount > ( **inGlobals ).itsInterleaveGroupFrameCount )
  948.             theFrameCount = ( **inGlobals ).itsInterleaveGroupFrameCount;
  949.         
  950.         theResult =
  951.             __PacketizeInterleaveGroup(
  952.                 &( **inGlobals ).itsAudioQueue, &thePayloadAttributes, theFrameCount,
  953.                 ( **inGlobals ).itsPacketBuilder );
  954.     }
  955.     
  956.     __UnlockInstanceData( inGlobals );
  957.     
  958.     return( theResult );
  959. }
  960.  
  961.  
  962.  
  963. #pragma mark -
  964. #pragma mark *        STANDARD COMPONENT INTERFACE
  965. #pragma mark -
  966. /* ---------------------------------------------------------------------------
  967.  *        S T A N D A R D    C O M P O N E N T    I N T E R F A C E
  968.  * ---------------------------------------------------------------------------
  969.  */
  970.  
  971. /* ---------------------------------------------------------------------------
  972.  *        + CallComponentOpen() implementation
  973.  * ---------------------------------------------------------------------------
  974.  *
  975.  *    Allocate and initialize storage for instance variables.  When a packetizer
  976.  *    is opened, it is not always called to packetize data, so this function
  977.  *    doesn't perform any allocations or time-consuming operations that are
  978.  *    needed only for packetizing sample data.  The RTPMPInitialize()
  979.  *    implementation performs such operations.
  980.  *
  981.  *    Since the RTPMPGetSettingsAsText() implementation and the
  982.  *    RTPMPDoUserDialog() implementation might be called before calling the
  983.  *    RTPMPInitialize() implementation, this function must initialize any
  984.  *    instance variables used by those functions.
  985.  *    
  986.  */
  987.  
  988. EXTERN_API( ComponentResult )
  989. RTPMPIMAAudio_Open(
  990.     RTPMPIMAAudioInstanceData **    inGlobals,
  991.     ComponentInstance                self )
  992. {
  993.     ComponentResult        theResult = noErr;
  994.     RTPMediaPacketizer    theBase;
  995.     
  996.     
  997.     inGlobals =
  998.         REINTERPRET_CAST( RTPMPIMAAudioInstanceData ** )(
  999.             NewHandleClear( sizeof( **inGlobals ) ) );
  1000.     
  1001.     if( inGlobals )
  1002.     {
  1003.         ( **inGlobals ).itself = self;
  1004.         ( **inGlobals ).itsFinalDerivation = self;
  1005.         ( **inGlobals ).itsInSystemHeap =
  1006.             ( HandleZone( REINTERPRET_CAST( Handle )( inGlobals ) ) == SystemZone() );
  1007.         ( **inGlobals ).itsLockCount = 0;
  1008.         ( **inGlobals ).itsInitialized = false;
  1009.         ( **inGlobals ).itsPayloadAttributesInitialized = false;
  1010.         
  1011.         IMAAudioPayloadInitialize( &( **inGlobals ).itsPayloadAttributes );
  1012.         
  1013.         SetComponentInstanceStorage( self, REINTERPRET_CAST( Handle )( inGlobals ) );
  1014.         
  1015.         theResult =
  1016.             OpenADefaultComponent(
  1017.                 kRTPMediaPacketizerType, kRTPBaseMediaPacketizerType, &theBase );
  1018.         
  1019.         if( theResult == noErr )
  1020.         {
  1021.             ( **inGlobals ).itsBase = theBase;
  1022.             theResult = CallComponentTarget( ( **inGlobals ).itsBase, self );
  1023.         }
  1024.     }
  1025.     
  1026.     else
  1027.     {
  1028.         theResult = MemError();
  1029.         
  1030.         if( theResult == noErr )
  1031.             theResult = memFullErr;
  1032.     }
  1033.     
  1034.     return( theResult );
  1035. }
  1036.  
  1037.  
  1038.  
  1039. /* ---------------------------------------------------------------------------
  1040.  *        + CallComponentClose() implementation
  1041.  * ---------------------------------------------------------------------------
  1042.  *
  1043.  *    Reverse the effects of the CallComponentOpen() implementation.
  1044.  *
  1045.  */
  1046.  
  1047. EXTERN_API( ComponentResult )
  1048. RTPMPIMAAudio_Close(
  1049.     RTPMPIMAAudioInstanceData **    inGlobals,
  1050.     ComponentInstance                self )
  1051. {
  1052. #pragma unused( self )
  1053.     
  1054.     IMAAudioQueue    theAudioQueue;
  1055.     
  1056.     
  1057.     if( inGlobals )
  1058.     {
  1059.         if( ( **inGlobals ).itsInitialized )
  1060.         {
  1061.             theAudioQueue = ( **inGlobals ).itsAudioQueue;
  1062.             IMAAudioQueueFlush( &theAudioQueue );
  1063.         }
  1064.         
  1065.         if( ( **inGlobals ).itsBase )
  1066.             CloseComponent( ( **inGlobals ).itsBase );
  1067.         
  1068.         DisposeHandle( REINTERPRET_CAST( Handle )( inGlobals ) );
  1069.     }
  1070.     
  1071.     return( noErr );
  1072. }
  1073.  
  1074.  
  1075.  
  1076. /* ---------------------------------------------------------------------------
  1077.  *        + CallComponentVersion() implementation
  1078.  * ---------------------------------------------------------------------------
  1079.  *
  1080.  *    Return the instance's version.
  1081.  *
  1082.  */
  1083.  
  1084. EXTERN_API( ComponentResult )
  1085. RTPMPIMAAudio_Version(
  1086.     RTPMPIMAAudioInstanceData **    inGlobals )
  1087. {
  1088. #pragma unused( inGlobals )
  1089.     
  1090.     return( kComponentVersion );
  1091. }
  1092.  
  1093.  
  1094.  
  1095. /* ---------------------------------------------------------------------------
  1096.  *        + CallComponentTarget() implementation
  1097.  * ---------------------------------------------------------------------------
  1098.  *
  1099.  *    Update the instance's inheritance graph with a new most-derived instance.
  1100.  *
  1101.  */
  1102.  
  1103. EXTERN_API( ComponentResult )
  1104. RTPMPIMAAudio_Target(
  1105.     RTPMPIMAAudioInstanceData **    inGlobals,
  1106.     ComponentInstance                target )
  1107. {
  1108.     ComponentResult        theResult;
  1109.     
  1110.     
  1111.     if( ( **inGlobals ).itsBase )
  1112.         theResult = ComponentSetTarget( ( **inGlobals ).itsBase, target );
  1113.     else
  1114.         theResult = noErr;
  1115.     
  1116.     if( theResult == noErr )
  1117.         ( **inGlobals ).itsFinalDerivation = target;
  1118.     
  1119.     return( theResult );
  1120. }
  1121.  
  1122.  
  1123.  
  1124. #pragma mark -
  1125. #pragma mark *        RTP MEDIA PACKETIZER INTERFACE
  1126. #pragma mark -
  1127. /* ---------------------------------------------------------------------------
  1128.  *        R T P    M E D I A    P A C K E T I Z E R    I N T E R F A C E
  1129.  * ---------------------------------------------------------------------------
  1130.  */
  1131.  
  1132. /* ---------------------------------------------------------------------------
  1133.  *        + RTPMPInitialize() implementation
  1134.  * ---------------------------------------------------------------------------
  1135.  *
  1136.  *    Prepare to packetize sample data.  This implementation initializes
  1137.  *    instance variables that represent the packetization state.
  1138.  *
  1139.  */
  1140.  
  1141. EXTERN_API( ComponentResult )
  1142. RTPMPIMAAudio_Initialize(
  1143.     RTPMPIMAAudioInstanceData **    inGlobals,
  1144.     SInt32                            inFlags )
  1145. {
  1146.     ComponentResult        theResult;
  1147.     
  1148.     
  1149.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPInitializeSelect ) )
  1150.         theResult = RTPMPInitialize( ( **inGlobals ).itsBase, inFlags );
  1151.     else
  1152.         theResult = noErr;
  1153.     
  1154.     if( theResult == noErr )
  1155.     {
  1156.         ( **inGlobals ).itsExpectedTimestamp = 0;
  1157.         ( **inGlobals ).itsPacketBuilder = NULL;
  1158.         ( **inGlobals ).itsPayloadSizeLimit = __kDefaultPacketSizeLimit;
  1159.         ( **inGlobals ).itsPayloadDurationLimit = __kDefaultPacketDurationLimit;
  1160.         ( **inGlobals ).itsInterleaveGroupFrameCount = 0;
  1161.         
  1162.         IMAAudioQueueInitialize( &( **inGlobals ).itsAudioQueue );
  1163.         
  1164.         ( **inGlobals ).itsInitialized = true;
  1165.     }
  1166.     
  1167.     return( theResult );
  1168. }
  1169.  
  1170.  
  1171.  
  1172. /* ---------------------------------------------------------------------------
  1173.  *        + RTPMPPreflightMedia() implementation
  1174.  * ---------------------------------------------------------------------------
  1175.  *
  1176.  *    Determine whether the packetizer can packetize data described by the
  1177.  *    given SampleDescription.  This implementation verifies that the sample
  1178.  *    data is in IMA Audio format.
  1179.  *
  1180.  */
  1181.  
  1182. EXTERN_API( ComponentResult )
  1183. RTPMPIMAAudio_PreflightMedia(
  1184.     RTPMPIMAAudioInstanceData **    inGlobals,
  1185.     OSType                            inMediaType,
  1186.     SampleDescriptionHandle            inSampleDescription )
  1187. {
  1188. #pragma unused( inGlobals )
  1189.     
  1190.     ComponentResult            theResult;
  1191.     SoundDescriptionHandle    theDescription;
  1192.     
  1193.     
  1194.     theDescription = REINTERPRET_CAST( SoundDescriptionHandle )( inSampleDescription );
  1195.     
  1196.     if(
  1197.         inMediaType != SoundMediaType  ||
  1198.         ( **theDescription ).dataFormat != kIMACompression )
  1199.     {
  1200.         theResult = qtsUnsupportedDataTypeErr;
  1201.     }
  1202.     
  1203.     else
  1204.     {
  1205.         theResult = noErr;
  1206.     }
  1207.     
  1208.     return( theResult );
  1209. }
  1210.  
  1211.  
  1212.  
  1213. /* ---------------------------------------------------------------------------
  1214.  *        + RTPMPSetSampleData() implementation
  1215.  * ---------------------------------------------------------------------------
  1216.  *
  1217.  *    Use the instance's RTPPacketBuilder to packetize the sample data described
  1218.  *    by the RTPMPSampleDataParams parameter.  The sample time of the data in
  1219.  *    successive calls is non-decreasing, but could be non-contiguous--that is,
  1220.  *    the data might have gaps.  This implementation guarantees that any queued
  1221.  *    data is always contiguous by flushing when it detects non-contiguous data.
  1222.  *    
  1223.  *    The RTPMPSampleDataParams structure includes a SampleDescription.  This
  1224.  *    implementation calls __UpdateSampleDescription() to detect when the
  1225.  *    SampleDescription changes and to make any updates necessary to accomodate
  1226.  *    the new SampleDescription.
  1227.  *
  1228.  *    The function then queues the sample data parameters and calls
  1229.  *    __ProcessAudioQueue() to packetize queued sample data.
  1230.  *
  1231.  */
  1232.  
  1233. EXTERN_API( ComponentResult )
  1234. RTPMPIMAAudio_SetSampleData(
  1235.     RTPMPIMAAudioInstanceData **    inGlobals,
  1236.     const RTPMPSampleDataParams *    inSampleData,
  1237.     SInt32 *                        outFlags )
  1238. {
  1239.     ComponentResult        theResult;
  1240.     SInt32                theFlags;
  1241.     
  1242.     
  1243.     /* Ignore requests that have no data */
  1244.     
  1245.     if( inSampleData->dataLength )
  1246.     {
  1247.         /* Flush before queueing non-contiguous data. */
  1248.         
  1249.         if( inSampleData->timeStamp !=     ( **inGlobals ).itsExpectedTimestamp )
  1250.             theResult = RTPMPFlush( ( **inGlobals ).itsFinalDerivation, 0, &theFlags );
  1251.         else
  1252.             theResult = noErr;
  1253.         
  1254.         if( theResult == noErr )
  1255.         {
  1256.             theResult = __UpdateSampleDescription( inGlobals, inSampleData );
  1257.             
  1258.             if( theResult == noErr )
  1259.             {
  1260.                 __LockInstanceData( inGlobals );
  1261.                 IMAAudioQueueEnqueue( &( **inGlobals ).itsAudioQueue, inSampleData );
  1262.                 __UnlockInstanceData( inGlobals );
  1263.                 
  1264.                 theResult = __ProcessAudioQueue( inGlobals, __kDontFlush );
  1265.                 
  1266.                 if( theResult == noErr )
  1267.                 {
  1268.                     ( **inGlobals ).itsExpectedTimestamp =
  1269.                         inSampleData->timeStamp + __SampleBlockDuration( inSampleData );
  1270.                 }
  1271.             }
  1272.         }
  1273.     }
  1274.     
  1275.     *outFlags = 0;
  1276.     
  1277.     return( theResult );
  1278. }
  1279.  
  1280.  
  1281.  
  1282. /* ---------------------------------------------------------------------------
  1283.  *        + RTPMPFlush() implementation
  1284.  * ---------------------------------------------------------------------------
  1285.  *
  1286.  *    Finish any packetization in progress.
  1287.  *
  1288.  */
  1289.  
  1290. EXTERN_API( ComponentResult )
  1291. RTPMPIMAAudio_Flush(
  1292.     RTPMPIMAAudioInstanceData **    inGlobals,
  1293.     SInt32                            inFlags,
  1294.     SInt32 *                        outFlags )
  1295. {
  1296.     ComponentResult        theResult;
  1297.     
  1298.     
  1299.     theResult = __ProcessAudioQueue( inGlobals, __kFlush );
  1300.     
  1301.     __LockInstanceData( inGlobals );
  1302.     IMAAudioQueueFlush( &( **inGlobals ).itsAudioQueue );
  1303.     __UnlockInstanceData( inGlobals );
  1304.     
  1305.     ( **inGlobals ).itsExpectedTimestamp = 0;
  1306.     
  1307.     if(
  1308.         theResult == noErr  &&
  1309.         CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPFlushSelect ) )
  1310.     {
  1311.         theResult = RTPMPFlush( ( **inGlobals ).itsBase, inFlags, outFlags );
  1312.     }
  1313.     
  1314.     else
  1315.     {
  1316.         *outFlags = 0;
  1317.     }
  1318.     
  1319.     return( theResult );
  1320. }
  1321.  
  1322.  
  1323.  
  1324. /* ---------------------------------------------------------------------------
  1325.  *        + RTPMPReset() implementation
  1326.  * ---------------------------------------------------------------------------
  1327.  *
  1328.  *    Abort any packetization in progress and prepare to packetize a new,
  1329.  *    possibly unrelated, data stream.  This implementation flushes its audio
  1330.  *    data queue, invalidates its cached payload attributes, and resets its
  1331.  *    base.
  1332.  *
  1333.  */
  1334.  
  1335. EXTERN_API( ComponentResult )
  1336. RTPMPIMAAudio_Reset(
  1337.     RTPMPIMAAudioInstanceData **    inGlobals,
  1338.     SInt32                            inFlags )
  1339. {
  1340.     ComponentResult        theResult;
  1341.     
  1342.     
  1343.     __LockInstanceData( inGlobals );
  1344.     IMAAudioQueueFlush( &( **inGlobals ).itsAudioQueue );
  1345.     __UnlockInstanceData( inGlobals );
  1346.     
  1347.     ( **inGlobals ).itsExpectedTimestamp = 0;
  1348.     ( **inGlobals ).itsPayloadAttributesInitialized = false;
  1349.     
  1350.     if( CallComponentCanDo( ( **inGlobals ).itsBase, kRTPMPResetSelect ) )
  1351.         theResult = RTPMPReset( ( **inGlobals ).itsBase, inFlags );
  1352.     else
  1353.         theResult = noErr;
  1354.     
  1355.     return( theResult );
  1356. }
  1357.  
  1358.  
  1359.  
  1360. /* ---------------------------------------------------------------------------
  1361.  *        + RTPMPGetInfo() implementation
  1362.  * ---------------------------------------------------------------------------
  1363.  *
  1364.  *    Return the information indicated by the selector.  This implemenation
  1365.  *    computes a result for the following selectors and delegates all others to
  1366.  *    its base.
  1367.  *
  1368.  *
  1369.  *        kRTPMPPayloadTypeInfo    ioParams points to an RTPMPPayloadTypeParams
  1370.  *                                structure.  This implementation fills in this
  1371.  *                                structure to indicate it uses a dynamic AVP
  1372.  *                                payload type.  It copies its payload encoding
  1373.  *                                name to a buffer described by this structure.
  1374.  *
  1375.  *        kRTPMPRTPTimeScaleInfo    ioParams points to a TimeScale where the
  1376.  *                                implementation returns the clock rate, in
  1377.  *                                Hertz, to be used for RTP timestamps.
  1378.  *
  1379.  *        kRTPMPMinPayloadSize    ioParams points to a UInt32 where the
  1380.  *                                implementation returns the number of octets
  1381.  *                                needed for the fixed header and payload
  1382.  *                                description used by this packetizer.
  1383.  *
  1384.  *        kRTPMPPayloadNameInfo    ioParams points to a Str255 where the
  1385.  *                                implementation returns a human-readable name
  1386.  *                                for the payload encoding used by this
  1387.  *                                packetizer.
  1388.  *
  1389.  */
  1390.  
  1391. EXTERN_API( ComponentResult )
  1392. RTPMPIMAAudio_GetInfo(
  1393.     RTPMPIMAAudioInstanceData **    inGlobals,
  1394.     OSType                            inSelector,
  1395.     void *                            ioParams )
  1396. {
  1397.     ComponentResult                theError = noErr;
  1398.     RTPMPPayloadTypeParams *    thePayloadInfo;
  1399.     Str255                        theEncodingName;
  1400.     
  1401.     
  1402.     switch( inSelector )
  1403.     {
  1404.         case kRTPMPPayloadTypeInfo:
  1405.             thePayloadInfo = STATIC_CAST( RTPMPPayloadTypeParams * )( ioParams );
  1406.             thePayloadInfo->flags = kRTPPayloadTypeDynamicFlag;
  1407.             thePayloadInfo->payloadNumber = kRTPPayload_Unknown;
  1408.             
  1409.             theError =
  1410.                 GetComponentIndString(
  1411.                     REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
  1412.                     theEncodingName, kRTPMPIMAAudioStringListResource,
  1413.                     kRTPMPIMAAudioProtocolEncodingString );
  1414.             
  1415.             if( !theError )
  1416.             {
  1417.                 if( thePayloadInfo->nameLength < ( theEncodingName[ 0 ] + 1 ) )
  1418.                 {
  1419.                     theError = paramErr;
  1420.                 }
  1421.                 
  1422.                 else
  1423.                 {
  1424.                     BlockMoveData(
  1425.                         &theEncodingName[ 1 ], thePayloadInfo->payloadName,
  1426.                         theEncodingName[ 0 ] );
  1427.                     
  1428.                     thePayloadInfo->payloadName[ theEncodingName[ 0 ] ] = '\0';
  1429.                 }
  1430.                 
  1431.                 thePayloadInfo->nameLength = theEncodingName[ 0 ] + 1;
  1432.             }
  1433.         break;
  1434.         
  1435.         
  1436.         case kRTPMPRTPTimeScaleInfo:
  1437.             *STATIC_CAST( TimeScale * )( ioParams ) = kIMAAudioPayloadRTPTimeScale;
  1438.         break;
  1439.         
  1440.         
  1441.         case kRTPMPMinPayloadSize:
  1442.             *STATIC_CAST( UInt32 * )( ioParams ) = sizeof( IMAAudioPayload );
  1443.         break;
  1444.         
  1445.         
  1446.         case kRTPMPPayloadNameInfo:
  1447.             theError =
  1448.                 GetComponentIndString(
  1449.                     REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
  1450.                     STATIC_CAST( StringPtr )( ioParams ),
  1451.                     kRTPMPIMAAudioStringListResource, kRTPMPIMAAudioHIEncodingString );
  1452.         break;
  1453.         
  1454.         
  1455.         case kRTPMPMinPacketDuration:
  1456.             theError = qtsBadSelectorErr;
  1457.         break;
  1458.         
  1459.         
  1460.         case kRTPMPRequiredSampleDescriptionInfo:
  1461.         case kRTPMPSuggestedRepeatPktCountInfo:
  1462.         case kRTPMPSuggestedRepeatPktSpacingInfo:
  1463.         case kRTPMPMaxPartialSampleSizeInfo:
  1464.         case kRTPMPPreferredBufferDelayInfo:
  1465.         default:
  1466.             theError = RTPMPGetInfo( ( **inGlobals ).itsBase, inSelector, ioParams );
  1467.         break;
  1468.     }
  1469.     
  1470.     return( theError );
  1471. }
  1472.  
  1473.  
  1474.  
  1475. /* ---------------------------------------------------------------------------
  1476.  *        + RTPMPSetTimeScale() implementation
  1477.  * ---------------------------------------------------------------------------
  1478.  */
  1479.  
  1480. EXTERN_API( ComponentResult )
  1481. RTPMPIMAAudio_SetTimeScale(
  1482.     RTPMPIMAAudioInstanceData **    inGlobals,
  1483.     TimeScale                        inTimeScale )
  1484. {
  1485.     ( **inGlobals ).itsMediaTimeScale = inTimeScale;
  1486.     
  1487.     return( noErr );
  1488. }
  1489.  
  1490.  
  1491.  
  1492. /* ---------------------------------------------------------------------------
  1493.  *        + RTPMPGetTimeScale() implementation
  1494.  * ---------------------------------------------------------------------------
  1495.  */
  1496.  
  1497. EXTERN_API( ComponentResult )
  1498. RTPMPIMAAudio_GetTimeScale(
  1499.     RTPMPIMAAudioInstanceData **    inGlobals,
  1500.     TimeScale *                        outTimeScale )
  1501. {
  1502.     *outTimeScale = ( **inGlobals ).itsMediaTimeScale;
  1503.     
  1504.     return( noErr );
  1505. }
  1506.  
  1507.  
  1508.  
  1509. /* ---------------------------------------------------------------------------
  1510.  *        + RTPMPSetTimeBase() implementation
  1511.  * ---------------------------------------------------------------------------
  1512.  */
  1513.  
  1514. EXTERN_API( ComponentResult )
  1515. RTPMPIMAAudio_SetTimeBase(
  1516.     RTPMPIMAAudioInstanceData **    inGlobals,
  1517.     TimeBase                        inTimeBase )
  1518. {
  1519.     ( **inGlobals ).itsMediaTimeBase = inTimeBase;
  1520.     
  1521.     return( noErr );
  1522. }
  1523.  
  1524.  
  1525.  
  1526. /* ---------------------------------------------------------------------------
  1527.  *        + RTPMPGetTimeBase() implementation
  1528.  * ---------------------------------------------------------------------------
  1529.  */
  1530.  
  1531. EXTERN_API( ComponentResult )
  1532. RTPMPIMAAudio_GetTimeBase(
  1533.     RTPMPIMAAudioInstanceData **    inGlobals,
  1534.     TimeBase *                        outTimeBase )
  1535. {
  1536.     *outTimeBase = ( **inGlobals ).itsMediaTimeBase;
  1537.     
  1538.     return( noErr );
  1539. }
  1540.  
  1541.  
  1542.  
  1543. /* ---------------------------------------------------------------------------
  1544.  *        + RTPMPHasCharacteristic() implementation
  1545.  * ---------------------------------------------------------------------------
  1546.  */
  1547.  
  1548. EXTERN_API( ComponentResult )
  1549. RTPMPIMAAudio_HasCharacteristic(
  1550.     RTPMPIMAAudioInstanceData **    inGlobals,
  1551.     OSType                            inSelector,
  1552.     Boolean *                        outHasIt )
  1553. {
  1554.     ComponentResult        theResult = noErr;
  1555.     
  1556.     
  1557.     switch( inSelector )
  1558.     {
  1559.         case kRTPMPNoSampleDataRequiredCharacteristic:
  1560.         case kRTPMPHasUserSettingsDialogCharacteristic:
  1561.             *outHasIt = true;
  1562.         break;
  1563.         
  1564.         
  1565.         case kRTPMPPartialSamplesRequiredCharacteristic:
  1566.         case kRTPMPPrefersReliableTransportCharacteristic:
  1567.         case kRTPMPRequiresOutOfBandDimensionsCharacteristic:
  1568.             *outHasIt = false;
  1569.         break;
  1570.         
  1571.         
  1572.         default:
  1573.             theResult =
  1574.                 RTPMPHasCharacteristic( ( **inGlobals ).itsBase, inSelector, outHasIt );
  1575.         break;
  1576.     }
  1577.     
  1578.     return( theResult );
  1579. }
  1580.  
  1581.  
  1582.  
  1583. /* ---------------------------------------------------------------------------
  1584.  *        + RTPMPSetPacketBuilder() implementation
  1585.  * ---------------------------------------------------------------------------
  1586.  */
  1587.  
  1588. EXTERN_API( ComponentResult )
  1589. RTPMPIMAAudio_SetPacketBuilder(
  1590.     RTPMPIMAAudioInstanceData **    inGlobals,
  1591.     ComponentInstance                inPacketBuilder )
  1592. {
  1593.     ComponentResult        theError;
  1594.     SInt32                theFlags;
  1595.     
  1596.     
  1597.     if( ( **inGlobals ).itsInitialized  &&  ( **inGlobals ).itsPacketBuilder )
  1598.         theError = RTPMPFlush( ( **inGlobals ).itsFinalDerivation, 0, &theFlags );
  1599.     else
  1600.         theError = noErr;
  1601.     
  1602.     if( !theError )
  1603.         ( **inGlobals ).itsPacketBuilder = inPacketBuilder;
  1604.     
  1605.     return( theError );
  1606. }
  1607.  
  1608.  
  1609.  
  1610. /* ---------------------------------------------------------------------------
  1611.  *        + RTPMPGetPacketBuilder() implementation
  1612.  * ---------------------------------------------------------------------------
  1613.  */
  1614.  
  1615. EXTERN_API( ComponentResult )
  1616. RTPMPIMAAudio_GetPacketBuilder(
  1617.     RTPMPIMAAudioInstanceData **    inGlobals,
  1618.     ComponentInstance *                outPacketBuilder )
  1619. {
  1620.     *outPacketBuilder = ( **inGlobals ).itsPacketBuilder;
  1621.     
  1622.     return( noErr );
  1623. }
  1624.  
  1625.  
  1626.  
  1627. /* ---------------------------------------------------------------------------
  1628.  *        + RTPMPSetMediaType() implementation
  1629.  * ---------------------------------------------------------------------------
  1630.  */
  1631.  
  1632. EXTERN_API( ComponentResult )
  1633. RTPMPIMAAudio_SetMediaType(
  1634.     RTPMPIMAAudioInstanceData **    inGlobals,
  1635.     OSType                            inMediaType )
  1636. {
  1637. #pragma unused( inGlobals )
  1638.     ComponentResult        theResult;
  1639.     
  1640.     
  1641.     if( inMediaType == SoundMediaType )
  1642.         theResult = noErr;
  1643.     else
  1644.         theResult = qtsBadDataErr;
  1645.     
  1646.     return( theResult );
  1647. }
  1648.  
  1649.  
  1650.  
  1651. /* ---------------------------------------------------------------------------
  1652.  *        + RTPMPGetMediaType() implementation
  1653.  * ---------------------------------------------------------------------------
  1654.  */
  1655.  
  1656. EXTERN_API( ComponentResult )
  1657. RTPMPIMAAudio_GetMediaType(
  1658.     RTPMPIMAAudioInstanceData **    inGlobals,
  1659.     OSType *                        outMediaType )
  1660. {
  1661. #pragma unused( inGlobals )
  1662.  
  1663.     *outMediaType = SoundMediaType;
  1664.     
  1665.     return( noErr );
  1666. }
  1667.  
  1668.  
  1669.  
  1670. /* ---------------------------------------------------------------------------
  1671.  *        + RTPMPSetMaxPacketSize() implementation
  1672.  * ---------------------------------------------------------------------------
  1673.  */
  1674.  
  1675. EXTERN_API( ComponentResult )
  1676. RTPMPIMAAudio_SetMaxPacketSize(
  1677.     RTPMPIMAAudioInstanceData **    inGlobals,
  1678.     UInt32                            inMaxPacketSize )
  1679. {
  1680.     ( **inGlobals ).itsPayloadSizeLimit = inMaxPacketSize;
  1681.     
  1682.     __UpdateLimits( inGlobals );
  1683.     
  1684.     return( noErr );
  1685. }
  1686.  
  1687.  
  1688.  
  1689. /* ---------------------------------------------------------------------------
  1690.  *        + RTPMPGetMaxPacketSize() implementation
  1691.  * ---------------------------------------------------------------------------
  1692.  */
  1693.  
  1694. EXTERN_API( ComponentResult )
  1695. RTPMPIMAAudio_GetMaxPacketSize(
  1696.     RTPMPIMAAudioInstanceData **    inGlobals,
  1697.     UInt32 *                        outMaxPacketSize )
  1698. {
  1699.     *outMaxPacketSize = ( **inGlobals ).itsPayloadSizeLimit;
  1700.     
  1701.     return( noErr );
  1702. }
  1703.  
  1704.  
  1705.  
  1706. /* ---------------------------------------------------------------------------
  1707.  *        + RTPMPSetMaxPacketDuration() implementation
  1708.  * ---------------------------------------------------------------------------
  1709.  */
  1710.  
  1711. EXTERN_API( ComponentResult )
  1712. RTPMPIMAAudio_SetMaxPacketDuration(
  1713.     RTPMPIMAAudioInstanceData **    inGlobals,
  1714.     UInt32                            inMaxPacketDuration )
  1715. {
  1716.     ( **inGlobals ).itsPayloadDurationLimit = inMaxPacketDuration;
  1717.     
  1718.     __UpdateLimits( inGlobals );
  1719.     
  1720.     return( noErr );
  1721. }
  1722.  
  1723.  
  1724.  
  1725. /* ---------------------------------------------------------------------------
  1726.  *        + RTPMPGetMaxPacketDuration() implementation
  1727.  * ---------------------------------------------------------------------------
  1728.  */
  1729.  
  1730. EXTERN_API( ComponentResult )
  1731. RTPMPIMAAudio_GetMaxPacketDuration(
  1732.     RTPMPIMAAudioInstanceData **    inGlobals,
  1733.     UInt32 *                        outMaxPacketDuration )
  1734. {
  1735.     *outMaxPacketDuration = ( **inGlobals ).itsPayloadDurationLimit;
  1736.     
  1737.     return( noErr );
  1738. }
  1739.  
  1740.  
  1741.  
  1742. /* ---------------------------------------------------------------------------
  1743.  *        + RTPMPDoUserDialog() implementation
  1744.  * ---------------------------------------------------------------------------
  1745.  *
  1746.  *    Present a dialog of user-adjustable options and update instance variables
  1747.  *    according to the user's choices.  This implementation allows the user to
  1748.  *    select an interleave count.
  1749.  *
  1750.  */
  1751.  
  1752. EXTERN_API( ComponentResult )
  1753. RTPMPIMAAudio_DoUserDialog(
  1754.     RTPMPIMAAudioInstanceData **    inGlobals,
  1755.     ModalFilterUPP                    inFilterUPP,
  1756.     Boolean *                        outCanceled )
  1757. {
  1758.     ComponentResult        theResult;
  1759.     ModalFilterUPP        theModalFilter;
  1760.     short                theItem;
  1761.     DialogPtr            theDialog;
  1762.     short                theSavedResources;
  1763.     short                theResources;
  1764.     short                theItemType;
  1765.     Rect                theItemRect;
  1766.     ControlHandle        theInterleavingMenu;
  1767.     UInt32                theInterleaveCount;
  1768.     
  1769.     
  1770.     theModalFilter = NewModalFilterProc( __SettingsDialogFilter );
  1771.     
  1772.     if( theModalFilter )
  1773.     {
  1774.         theSavedResources = CurResFile();
  1775.         
  1776.         theResources =
  1777.             OpenComponentResFile( REINTERPRET_CAST( Component )( ( **inGlobals ).itself ) );
  1778.         
  1779.         if( theResources > 0 )
  1780.         {
  1781.             theDialog =
  1782.                 GetNewDialog(
  1783.                     kRTPMPIMAAudioSettingsDialogResource, NULL,
  1784.                     REINTERPRET_CAST( WindowPtr )( -1L ) );
  1785.             
  1786.             if( theDialog )
  1787.             {
  1788.                 SetDialogDefaultItem( theDialog, __kOKButton );
  1789.                 SetDialogCancelItem( theDialog, __kCancelButton );
  1790.                 
  1791.                 GetDialogItem(
  1792.                     theDialog, __kInterleavingMenu, &theItemType,
  1793.                     REINTERPRET_CAST( Handle * )( &theInterleavingMenu ), &theItemRect );
  1794.                 
  1795.                 theInterleaveCount =
  1796.                     IMAAudioPayloadInterleaveCount( &( **inGlobals ).itsPayloadAttributes );
  1797.                 
  1798.                 if( theInterleaveCount > 1 )
  1799.                     theInterleaveCount++;
  1800.                 
  1801.                 SetControlValue( theInterleavingMenu, theInterleaveCount );
  1802.                 HiliteControl( theInterleavingMenu, kControlNoPart );
  1803.                 
  1804.                 MacShowWindow( theDialog );
  1805.                 
  1806.                 if( theModalFilter )
  1807.                     SetWRefCon( theDialog, REINTERPRET_CAST( long )( inFilterUPP ) );
  1808.                 else
  1809.                     theModalFilter = inFilterUPP;
  1810.                 
  1811.                 do
  1812.                 {
  1813.                     ModalDialog( theModalFilter, &theItem );
  1814.                 }
  1815.                 while( theItem != __kOKButton  && theItem != __kCancelButton );
  1816.                 
  1817.                 if( theItem == __kOKButton )
  1818.                 {
  1819.                     theInterleaveCount = GetControlValue( theInterleavingMenu );
  1820.                     
  1821.                     if( theInterleaveCount > 2 )
  1822.                         --theInterleaveCount;
  1823.                     
  1824.                     IMAAudioPayloadSetInterleaving(
  1825.                         &( **inGlobals ).itsPayloadAttributes, theInterleaveCount, 0 );
  1826.                 }
  1827.                 
  1828.                 *outCanceled = ( theItem == __kCancelButton );
  1829.                 
  1830.                 DisposeDialog( theDialog );
  1831.             }
  1832.             
  1833.             else
  1834.             {
  1835.                 theResult = ResError();
  1836.                 
  1837.                 if( theResult == noErr )
  1838.                     theResult = memFullErr;
  1839.             }
  1840.             
  1841.             UseResFile( theSavedResources );
  1842.             CloseComponentResFile( theResources );
  1843.             
  1844.             theResult = noErr;
  1845.         }
  1846.         
  1847.         else
  1848.         {
  1849.             theResult = ResError();
  1850.             
  1851.             if( theResult == noErr )
  1852.                 theResult = memFullErr;
  1853.         }
  1854.         
  1855.         DisposeRoutineDescriptor( theModalFilter );
  1856.     }
  1857.     
  1858.     else
  1859.     {
  1860.         theResult = MemError();
  1861.         
  1862.         if( theResult == noErr )
  1863.             theResult = memFullErr;
  1864.     }
  1865.     
  1866.     return( theResult );
  1867. }
  1868.  
  1869.  
  1870.  
  1871. /* ---------------------------------------------------------------------------
  1872.  *        + RTPMPSetSettingsFromAtomContainerAtAtom() implementation
  1873.  * ---------------------------------------------------------------------------
  1874.  *
  1875.  *    Update instance variables according to the saved user settings in the
  1876.  *    given atom container.
  1877.  *
  1878.  */
  1879.  
  1880. EXTERN_API( ComponentResult )
  1881. RTPMPIMAAudio_SetSettingsFromAtomContainerAtAtom(
  1882.     RTPMPIMAAudioInstanceData **    inGlobals,
  1883.     QTAtomContainer                    inAtomContainer,
  1884.     QTAtom                            inParentAtom )
  1885. {
  1886.     ComponentResult                theResult = noErr;
  1887.     QTAtom                        theAtom;
  1888.     QTAtomID                    theAtomID;
  1889.     Ptr                            theAtomData;
  1890.     long                        theDataSize;
  1891.     __TStoredInterleaveCount    theInterleaveCount;
  1892.     
  1893.     
  1894.     if( inAtomContainer )
  1895.     {
  1896.         theAtom =
  1897.             QTFindChildByIndex(
  1898.                 inAtomContainer, inParentAtom, __kInterleaveCountAtomType, 1, &theAtomID );
  1899.         
  1900.         if( theAtom )
  1901.         {
  1902.             QTLockContainer( inAtomContainer );
  1903.             
  1904.             QTGetAtomDataPtr(
  1905.                 inAtomContainer, theAtom, &theDataSize, &theAtomData );
  1906.             
  1907.             if( theDataSize == sizeof( theInterleaveCount ) )
  1908.             {
  1909.                 /* Convert from storage byte order to platform byte order. */
  1910.                 
  1911.                 theInterleaveCount =
  1912.                     EndianU32_BtoN(
  1913.                         *REINTERPRET_CAST( __TStoredInterleaveCount * )(
  1914.                             theAtomData ) );
  1915.                 
  1916.                 if( theInterleaveCount > kIMAAudioPayloadInterleaveCountLimit )
  1917.                 {
  1918.                     theResult = qtsBadDataErr;
  1919.                 }
  1920.                 
  1921.                 else
  1922.                 {
  1923.                     IMAAudioPayloadSetInterleaving(
  1924.                         &( **inGlobals ).itsPayloadAttributes, theInterleaveCount, 0 );
  1925.                 }
  1926.             }
  1927.             
  1928.             else
  1929.             {
  1930.                 theResult = qtsBadDataErr;
  1931.             }
  1932.             
  1933.             QTUnlockContainer( inAtomContainer );
  1934.         }
  1935.     }
  1936.     
  1937.     else
  1938.     {
  1939.         theResult = paramErr;
  1940.     }
  1941.  
  1942.     return( theResult );
  1943. }
  1944.  
  1945.  
  1946.  
  1947. /* ---------------------------------------------------------------------------
  1948.  *        + RTPMPGetSettingsIntoAtomContainerAtAtom() implementation
  1949.  * ---------------------------------------------------------------------------
  1950.  *
  1951.  *    Return current settings of user-adjustable options in the given atom
  1952.  *    container.
  1953.  *
  1954.  */
  1955.  
  1956. EXTERN_API( ComponentResult )
  1957. RTPMPIMAAudio_GetSettingsIntoAtomContainerAtAtom(
  1958.     RTPMPIMAAudioInstanceData **    inGlobals,
  1959.     QTAtomContainer                    inOutAtomContainer,
  1960.     QTAtom                            inParentAtom )
  1961. {
  1962.     ComponentResult                theResult;
  1963.     QTAtom                        theAtom;
  1964.     QTAtomID                    theAtomID;
  1965.     __TStoredInterleaveCount    theInterleaveCount;
  1966.     
  1967.     
  1968.     if( inOutAtomContainer )
  1969.     {
  1970.         /* Convert from platform byte order to storage byte order. */
  1971.         
  1972.         theInterleaveCount =
  1973.             EndianU32_NtoB(
  1974.                 IMAAudioPayloadInterleaveCount( &( **inGlobals ).itsPayloadAttributes ) );
  1975.         
  1976.         
  1977.         /* If the atom already exists, update it.  Otherwise, insert a new one. */
  1978.         
  1979.         theAtom =
  1980.             QTFindChildByIndex(
  1981.                 inOutAtomContainer, inParentAtom, __kInterleaveCountAtomType, 1, &theAtomID );
  1982.         
  1983.         if( theAtom )
  1984.         {
  1985.             theResult =
  1986.                 QTSetAtomData(
  1987.                     inOutAtomContainer, theAtom, sizeof( theInterleaveCount ),
  1988.                     &theInterleaveCount );
  1989.         }
  1990.         
  1991.         else
  1992.         {
  1993.             theResult =
  1994.                 QTInsertChild(
  1995.                     inOutAtomContainer, inParentAtom, __kInterleaveCountAtomType,
  1996.                     0 /* id */, 0 /* index */, sizeof( theInterleaveCount ),
  1997.                     &theInterleaveCount, NULL /* atom */);
  1998.         }
  1999.     }
  2000.     
  2001.     else
  2002.     {
  2003.         theResult = paramErr;
  2004.     }
  2005.     
  2006.     return( theResult );
  2007. }
  2008.  
  2009.  
  2010.  
  2011. /* ---------------------------------------------------------------------------
  2012.  *        + RTPMPGetMediaSettingsAsText() implementation
  2013.  * ---------------------------------------------------------------------------
  2014.  *
  2015.  *    Return current settings of user-adjustable options as a string.  This
  2016.  *    implementation returns the interleave count as colon-delimited name-value
  2017.  *    pair:
  2018.  *
  2019.  *        "Interleaving: <interleave count>"
  2020.  *
  2021.  *            or
  2022.  *
  2023.  *        "Interleaving: None"
  2024.  *
  2025.  */
  2026.  
  2027. EXTERN_API( ComponentResult )
  2028. RTPMPIMAAudio_GetSettingsAsText(
  2029.     RTPMPIMAAudioInstanceData **    inGlobals,
  2030.     Handle *                        text )
  2031. {
  2032.     ComponentResult        theResult;
  2033.     Str255                theSettings;
  2034.     UInt32                theInterleaveCount;
  2035.     unsigned char        theSavedCharacter;
  2036.     int                    theLength;
  2037.     
  2038.     
  2039.     theResult =
  2040.         GetComponentIndString(
  2041.             REINTERPRET_CAST( Component )( ( **inGlobals ).itself ), theSettings,
  2042.             kRTPMPIMAAudioStringListResource, kRTPMPIMAAudioSettingsString );
  2043.     
  2044.     if( theResult == noErr )
  2045.     {
  2046.         theLength = theSettings[ 0 ];
  2047.         theSavedCharacter = theSettings[ theLength ];
  2048.         
  2049.         theInterleaveCount =
  2050.             IMAAudioPayloadInterleaveCount( &( **inGlobals ).itsPayloadAttributes );
  2051.         
  2052.         if( theInterleaveCount > 1 )
  2053.         {
  2054.             NumToString( theInterleaveCount, &theSettings[ theLength ] );
  2055.         }
  2056.         
  2057.         else
  2058.         {
  2059.             GetComponentIndString(
  2060.                 REINTERPRET_CAST( Component )( ( **inGlobals ).itself ),
  2061.                 &theSettings[ theLength ], kRTPMPIMAAudioStringListResource,
  2062.                 kRTPMPIMAAudioNoInterleavingString );
  2063.         }
  2064.         
  2065.         theSettings[ 0 ] += theSettings[ theLength ];
  2066.         theSettings[ theLength ] = theSavedCharacter;
  2067.         theLength = theSettings[ 0 ];
  2068.         
  2069.         *text = NewHandle( theLength );
  2070.         
  2071.         if( *text )
  2072.             BlockMoveData( &theSettings[ 1 ], **text, theLength );
  2073.         else
  2074.             theResult = MemError();
  2075.     }
  2076.     
  2077.     else
  2078.     {
  2079.         *text = 0;
  2080.     }
  2081.     
  2082.     return( theResult );
  2083. }
  2084.